{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 基于streamlit的大模型应用开发——问答与记忆"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "#导入语言模型\n",
    "import os\n",
    "from langchain_community.llms import Tongyi\n",
    "from langchain_community.llms import SparkLLM\n",
    "from langchain_community.llms import QianfanLLMEndpoint\n",
    "\n",
    "import pandas as pd\n",
    "#导入模版\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "#导入聊天模型\n",
    "from langchain.prompts.chat import (\n",
    "    ChatPromptTemplate,\n",
    "    SystemMessagePromptTemplate,\n",
    "    AIMessagePromptTemplate,\n",
    "    HumanMessagePromptTemplate,\n",
    ")\n",
    "from langchain.schema import (\n",
    "    AIMessage,\n",
    "    HumanMessage,\n",
    "    SystemMessage\n",
    ")\n",
    "\n",
    "from langchain_community.chat_models import ChatSparkLLM\n",
    "from langchain_community.chat_models.tongyi import ChatTongyi\n",
    "from langchain_community.chat_models import QianfanChatEndpoint\n",
    "\n",
    "#输入三个模型各自的key\n",
    "\n",
    "os.environ[\"DASHSCOPE_API_KEY\"] = \"\"\n",
    "\n",
    "os.environ[\"IFLYTEK_SPARK_APP_ID\"] = \"\"\n",
    "os.environ[\"IFLYTEK_SPARK_API_KEY\"] = \"\"\n",
    "os.environ[\"IFLYTEK_SPARK_API_SECRET\"] = \"\"\n",
    "\n",
    "os.environ[\"QIANFAN_AK\"] = \"\"\n",
    "os.environ[\"QIANFAN_SK\"] = \"\"\n",
    "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "model_ty = Tongyi(temperature=0)\n",
    "model_qf = QianfanLLMEndpoint(model=\"ERNIE-Bot\")\n",
    "chat_qf = QianfanChatEndpoint(model=\"ERNIE-Bot\")\n",
    "chat_xh = ChatSparkLLM()\n",
    "chat_ty= ChatTongyi()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'0.1.16'"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import langchain\n",
    "langchain.__version__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "#! pip install --upgrade langchain -i https://mirrors.aliyun.com/pypi/simple"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## langchain的大模型对话应用的实现\n",
    "\n",
    "\n",
    "### 简单对话"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'你好！有什么我能为你做的吗？'"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model_ty = Tongyi(temperature=0)\n",
    "model_ty.invoke(\"你好\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* streamlit的知识点\n",
    "\n",
    "1. st.title()\n",
    "2. st.write()\n",
    "3. st.chat_input()\n",
    "4. st.chat_message\n",
    "5. python中冒号+等于号的作用\n",
    "\n",
    "* 运行方法:打开终端——运行 streamlit run 文件地址"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import streamlit as st"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#! pip install streamlit -i https://mirrors.aliyun.com/pypi/simple"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "30 is greater than 10\n",
      "30 is greater than 10\n"
     ]
    }
   ],
   "source": [
    "# without walrus\n",
    "n = 30\n",
    "if n > 10:\n",
    "    print(f\"{n} is greater than 10\")\n",
    "\n",
    "# with walrus\n",
    "if (n := 30) > 10:\n",
    "    print(f\"{n} is greater than 10\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* classwork 1\n",
    "\n",
    "完成最简单大模型问答应用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 带记忆对话\n",
    "\n",
    "大多数的 LLM 应用程序都会有一个会话接口，允许我们和 LLM 进行多轮的对话，并有一定的上下文记忆能力。但实际上，模型本身是不会记忆任何上下文的，只能依靠用户本身的输入去产生输出。而实现这个记忆功能，就需要额外的模块去保存我们和模型对话的上下文信息，然后在下一次请求时，把所有的历史信息都输入给模型，让模型输出最终结果。\n",
    "\n",
    "而在 LangChain 中，提供这个功能的模块就称为 Memory，用于存储用户和模型交互的历史信息。在 LangChain 中根据功能和返回值的不同，会有多种不同的 Memory 类型，主要可以分为以下几个类别：\n",
    "\n",
    "* 对话缓冲区内存（ConversationBufferMemory），最基础的内存模块，用于存储历史的信息\n",
    "* 对话缓冲器窗口内存（ConversationBufferWindowMemory），只保存最后的 K 轮对话的信息，因此这种内存空间使用会相对较少\n",
    "* 对话摘要内存（ConversationSummaryMemory），这种模式会对历史的所有信息进行抽取，生成摘要信息，然后将摘要信息作为历史信息进行保存。\n",
    "* 对话摘要缓存内存（ConversationSummaryBufferMemory），这个和上面的作用基本一致，但是有最大 token 数的限制，达到这个最大 token 数的时候就会进行合并历史信息生成摘要\n",
    "\n",
    "值得注意的是，对话摘要内存的设计出发点就是语言模型能支持的上下文长度是有限的（一般是 2048），超过了这个长度的数据天然的就被截断了。这个类会根据对话的轮次进行合并，默认值是 2，也就是每 2 轮就开启一次调用 LLM 去合并历史信息。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import ConversationChain\n",
    "from langchain.memory import ConversationBufferMemory\n",
    "\n",
    "a1=ConversationBufferMemory()\n",
    "\n",
    "conversation = ConversationChain(\n",
    "    llm=model_ty,  \n",
    "    memory=a1\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'input': '你好',\n",
       " 'history': '',\n",
       " 'response': '你好！有什么问题或者需要帮助的吗？我可以提供各种信息，从天气预报到科技新闻，从食谱建议到历史事件的详情。只要告诉我你感兴趣的话题，我们就可以聊起来！'}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.invoke(\"你好\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[HumanMessage(content='你好'),\n",
       " AIMessage(content='你好！有什么问题或者需要帮助的吗？我可以提供各种信息，从天气预报到科技新闻，从食谱建议到历史事件的详情。只要告诉我你感兴趣的话题，我们就可以聊起来！')]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.memory.chat_memory.messages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'human'"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a1.chat_memory.messages[0].type"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[HumanMessage(content='你好'),\n",
       " AIMessage(content='你好！有什么问题或者需要帮助的吗？我可以提供各种信息，从天气预报到科技新闻，从食谱建议到历史事件的详情。只要告诉我你感兴趣的话题，我们就可以聊起来！')]"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a1.chat_memory.messages"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* streamlit的会话状态与回调方式(session_state)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if 'history' not in st.session_state:\n",
    "    st.session_state['history'] = []"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* classwork 2\n",
    "\n",
    "完成带记忆的大模型问答应用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基于streamlit的大模型问答应用实现-通义千问\n",
    "\n",
    "* 原生通义千问问答实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "import dashscope\n",
    "from dashscope import Generation\n",
    "from langchain.tools.render import render_text_description\n",
    "import streamlit as st\n",
    "\n",
    "dashscope.api_key = \"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt=[]\n",
    "\n",
    "def get_response(mess):\n",
    "    response = Generation.call(\n",
    "        model='qwen-turbo',\n",
    "        messages=mess,\n",
    "        result_format='message', # 将输出设置为message形式\n",
    "    )\n",
    "    return response\n",
    "\n",
    "def prompt_yun(ct):\n",
    "    prompt.append({\"role\":\"user\",\"content\":ct})\n",
    "    return prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "p_y=prompt_yun(\"你好\")\n",
    "res=get_response(p_y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'你好！很高兴能为你服务。有什么可以帮助你的吗？'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.output.choices[0].message['content']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 带记忆的对话问答的streamlit实现-通义千问\n",
    "\n",
    "* 原生通义千问的记忆方案\n",
    "\n",
    "* classwork 3 \n",
    "\n",
    "1. 完成通义千问问答简单搭建\n",
    "2. 完成带记忆的通义千问问答应用的搭建"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 应用打包\n",
    "\n",
    "https://blog.csdn.net/Helloorld_1/article/details/131767478\n",
    "\n",
    "https://blog.csdn.net/nexttoparadise/article/details/135368387\n",
    "\n",
    "* langchain官方文档对话\n",
    "\n",
    "https://chat.langchain.com/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
